package com.fwtai.service;

import com.fwtai.tool.ToolClient;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.concurrent.Callable;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**异步处理任务*/
public final class AsyncResultService{

  private final ThreadPoolExecutor executor;

  /**
   * 创建独立线程池，做到线程隔离
   * @param maximumPoolSize 76800
   * @param capacity 51200
  */
  public AsyncResultService(final int maximumPoolSize,final int capacity){
    executor = new ThreadPoolExecutor(
      Runtime.getRuntime().availableProcessors()*32,maximumPoolSize,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<>(capacity),new ThreadPoolExecutor.CallerRunsPolicy()
    );
  }

  /**有返回值*/
  public DeferredResult<String> asyncHandler(final Callable<String> action){
    final DeferredResult<String> result = new DeferredResult<>();
    final Runnable beforeCallable = () -> {
      try {
        result.setResult(action.call());
      } catch (final Exception e){
        result.setErrorResult(ToolClient.exceptionJson("系统出现错误,稍候重试"));
      }
    };
    executor.execute(beforeCallable);
    return result;
  }

  /**无返回值*/
  public void asyncHandler(final Runnable runnable){
    executor.execute(runnable);
  }

  /**
   * 带超时的异步任务
   * @param timeoutValue 是毫秒数,如60*1000L是1分钟超时
   * 用法:
      return new AsyncResultService().asyncHandler(taskExecutor,new Callable<String>(){
        @Override
        public String call() throws Exception{
          return ToolClient.queryJson(apiHomeDao.getCarousel());
        }
      },30*1000L);//设定30秒超时
  */
  public DeferredResult<String> asyncHandler(final Callable<String> action,final Long timeoutValue){
    final DeferredResult<String> result = new DeferredResult<>(timeoutValue);//todo 不传值时系统默认的是1分钟,即60*1000L
    //处理超时事件 采用委托机制
    result.onTimeout(() -> {
      result.setResult(ToolClient.exceptionJson("系统出现错误,处理超时"));
    });
    final Runnable beforeCallable = () -> {
      try {
        result.setResult(action.call());
      } catch (final Exception e){
        result.setErrorResult(ToolClient.exceptionJson("系统出现错误,稍候重试"));
      }
    };
    executor.execute(beforeCallable);
    return result;
  }
}